﻿using System;
using System.Collections.Generic;
using System.Text;

using Yuyi.PluginForJS.JavaScriptLexer;

namespace Yuyi.PluginForJS.JavaScriptParser
{
    public class Parser
    {
        Lexer lexer;
        Token CurrentToken { get { return lexer.CurrentToken; } }
        
        public Parser(Lexer lexer)
        {
            this.lexer = lexer;
        }
        public AST Parse()
        {
            try
            {
                return ParseElements();
            }
            catch { return null; }
            
        }
        private void Match(int kind)
        {
            if (CurrentToken.kind == kind) lexer.GetNextToken();
        }
        /// <summary>
        /// Elements
        /// :Element
        /// |EOF
        /// ;
        /// </summary>
        /// <returns>ast</returns>
        private AST ParseElements()
        {
            AST root = new AST();
            while (CurrentToken.kind != Tokens.EOF)
            {
                AST child = ParseElement();
                if(child != null)
                    root.ChildNodes.Add(child);
            }
            return root;
        }
        /// <summary>
        /// Element
        /// :FunctionDeclaration
        /// |Statement
        /// ;
        /// </summary>
        /// <returns>ast</returns>
        private AST ParseElement()
        {
            AST statement = null;
            if (CurrentToken.kind == Tokens.Function)
                statement = ParseFunctionDeclaration(true);
            else
                statement = ParseStatement();
            return statement;
        }
        /// <summary>
        /// FunctionDeclaration
        /// :Function Identifier OpenParenthesis FormalParameterList? CloseParenthesis OpenCurlyBrace FunctionBody CloseCurlyBrace
        /// ;
        ///FunctionExpression
        ///: Function Identifier? OpenParenthesis FormalParameterList? CloseParenthesis OpenCurlyBrace FunctionBody CloseCurlyBrace
        ///;
        /// </summary>
        /// <param name="identifierRequired"></param>
        /// <returns>ast</returns>
        private AST ParseFunctionDeclaration(bool identifierRequired)
        {
            FunctionNode result = null;
            string name = null;
            AST body = null;
            AST parameters = new AST() ;
            parameters.NodeKind = Nodes.Empty;

            Match(Tokens.Function);
            if (CurrentToken.kind == Tokens.Identifier)
            {
                name = CurrentToken.value;
                Match(Tokens.Identifier);
            }
            else if (identifierRequired)
            {
                throw new Exception("error");
            }
            Match(Tokens.OpenParenthesis);
            if (CurrentToken.kind == Tokens.Identifier)
            {
                parameters = ParseFormalParameterList();
            }
            Match(Tokens.CloseParenthesis);
            Match(Tokens.OpenCurlyBrace);
            body = ParseFunctionBody();
            Match(Tokens.CloseCurlyBrace);
            result = new FunctionNode();
            if (!string.IsNullOrEmpty(name))
                result.Name = name;
            result.ChildNodes.Add(parameters);
            result.ChildNodes.Add(body);
            return result;
        }
        /// <summary>
        /// FormalParameterList
        /// : Identifier
        /// |Identifier Comma FormalParameterList
        /// ;
        /// </summary>
        /// <returns></returns>
        private AST ParseFormalParameterList()
        {
            AST result = new AST();
            result.NodeKind = Nodes.formalParameterList;
            AST name = new AST();
            name.NodeKind = Nodes.Identifier;
            name.Name = CurrentToken.value;
            result.ChildNodes.Add(name);
            Match(Tokens.Identifier);
            while (CurrentToken.kind == Tokens.Comma)
            {
                Match(Tokens.Comma);
                if (CurrentToken.kind == Tokens.Identifier)
                {
                    name = new AST();
                    name.NodeKind = Nodes.Identifier;
                    name.Name = CurrentToken.value;
                    result.ChildNodes.Add(name);
                    Match(Tokens.Identifier);
                }
            }
            return result;
        }
        /// <summary>
        /// FunctionBody
        /// :Elements
        /// ;
        /// </summary>
        /// <returns></returns>
        private AST ParseFunctionBody()
        {
            AST result = new AST();
            result.NodeKind = Nodes.sourceElements;
            while (CurrentToken.kind != Tokens.CloseCurlyBrace && CurrentToken.kind != Tokens.EOF)
            {
                AST statement;
                if (CurrentToken.kind == Tokens.Function)
                {
                    statement = ParseFunctionDeclaration(false);
                }
                else
                {
                    statement = ParseStatement();
                }
                result.ChildNodes.Add(statement);
            }
            return result;
        }
        private AST ParseStatement()
        {
            AST statement;
            switch (CurrentToken.kind)
            {
                case Tokens.OpenCurlyBrace: return ParseBlock();
                case Tokens.Break:return ParseBreakStatement();
                case Tokens.Continue:return ParseContinueStatement();
                case Tokens.EndOfLine:
                case Tokens.Semicolon: 
                    { 
                        statement = new AST();
                        statement.NodeKind = Nodes.Empty;
                        Match(Tokens.EndOfLine);
                        Match(Tokens.Semicolon);
                        return statement;
                    };
                case Tokens.For: return ParseForStatement();
                case Tokens.Identifier: return ParseLabelledStatement();
                case Tokens.If: return ParseIfStatement();
                case Tokens.Do: return ParseDoStatement();
                case Tokens.Return:return ParseReturnStatement();
                case Tokens.Switch: return ParseSwitchStatement();
                case Tokens.Throw: return ParseThrowStatement();
                case Tokens.Try: return ParseTryStatement();
                case Tokens.Var: 
                    {
                        statement = ParseVarExpression(false); 
                        Match(Tokens.Semicolon);
                        Match(Tokens.EndOfLine);
                        return statement;
                    }
                case Tokens.While: return ParseWhileStatement();
                case Tokens.With: return ParseWithStatement();
                case Tokens.Else: return ParseElement();
                default: {
                    lexer.GetNextToken();
                    return null;
                }
            }
        }

        private AST ParseLabelledStatement()
        {
            AST result;
            result = ParseExpression(false);
            if (CurrentToken.kind == Tokens.Colon)
            {
                AST label = new AST();
                label.NodeKind = Nodes.Identifier;
                Match(Tokens.Colon);
                AST statment = ParseStatement();
                result = new AST();
                result.NodeKind = Nodes.Label;
                result.ChildNodes.Add(label);
                result.ChildNodes.Add(statment);
            }
            Match(Tokens.Semicolon);
            return result;
        }

        private AST ParseThrowStatement()
        {
            AST result;
            Match(Tokens.Throw);
            AST exp = ParseExpression(false);
            result = new AST();
            result.NodeKind = Nodes.Throw;
            result.ChildNodes.Add(exp);
            Match(Tokens.Semicolon);
            return result;
        }

        private AST ParseTryStatement()
        {
            AST result = new AST();
            result.NodeKind = Nodes.Try;

            AST body;
            AST catchNode = new AST();
            catchNode.NodeKind = Nodes.Empty;
            AST finallyNode = new AST();
            finallyNode.NodeKind = Nodes.Empty;

            Match(Tokens.Try);
            body = ParseBlock();
            if (CurrentToken.kind == Tokens.Catch)
            {
                catchNode = ParseCatch();
            }
            if (CurrentToken.kind == Tokens.Finally)
            {
                finallyNode = ParseFinally();
            }
            if (catchNode == null && finallyNode == null)
            {
                throw new Exception("must have one catch or one finally");
            }
            result.ChildNodes.Add(body);
            result.ChildNodes.Add(catchNode);
            result.ChildNodes.Add(finallyNode);

            return result;
        }

        private AST ParseFinally()
        {
            Match(Tokens.Finally);
            AST body = ParseBlock();
            AST result = new AST();
            result.NodeKind = Nodes.Finally;
            result.ChildNodes.Add(body);
            return result;
        }

        private AST ParseCatch()
        {
            AST name;
            Match(Tokens.Catch);
            Match(Tokens.OpenParenthesis);
            if (CurrentToken.kind != Tokens.Identifier)
            {
                throw new Exception("There must a Identifier");
            }
            name = new AST();
            name.NodeKind = Nodes.Identifier;
            name.Name = CurrentToken.value;
            Match(Tokens.Identifier);
            Match(Tokens.CloseParenthesis);

            AST body = ParseBlock();
            AST result = new AST();
            result.NodeKind = Nodes.Catch;
            result.ChildNodes.Add(name);
            result.ChildNodes.Add(body);
            return result;
        }

        private AST ParseSwitchStatement()
        {
            AST result;

            bool hasDefault = false;

            Match(Tokens.Switch);
            Match(Tokens.OpenParenthesis);
            AST exp = ParseExpression(false);
            result = new AST();
            result.NodeKind = Nodes.Switch;
            result.ChildNodes.Add(exp);
            Match(Tokens.CloseParenthesis);
            Match(Tokens.OpenCurlyBrace);
            while (CurrentToken.kind != Tokens.CloseCurlyBrace && CurrentToken.kind != Tokens.EOF)
            {
                AST block = ParseCaseOrDefaultBlock();
                if (block.NodeKind == Nodes.Default)
                {
                    if (hasDefault)
                    {
                        throw new Exception("Only allow one default");
                    }
                    else
                    { 
                        hasDefault = true;
                    }
                    
                }
                result.ChildNodes.Add(block);
            }
            Match(Tokens.CloseCurlyBrace);
            return result;
        }

        private AST ParseCaseOrDefaultBlock()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// WithStatement
	   ///    	:    WITH LPAREN Expression RPAREN Statement
	   ///    	;
        /// </summary>
        /// <returns></returns>
        private AST ParseWithStatement()
        {
            AST result;
            AST exp;
            AST body;
            Match(Tokens.With);
            Match(Tokens.OpenParenthesis);
            exp = ParseExpression(false);
            Match(Tokens.CloseParenthesis);
            body = ParseStatement();
            result = new AST();
            result.NodeKind = Nodes.With;
            result.ChildNodes.Add(exp);
            result.ChildNodes.Add(body);
            return result;
        }

        private AST ParseReturnStatement()
        {
            AST result;

            AST expression = new AST();
            expression.NodeKind = Nodes.Empty;

            Match(Tokens.Return);

            expression = ParseExpression(false);
            result = new AST();
            result.NodeKind = Nodes.Return;
            result.ChildNodes.Add(expression);
            Match(Tokens.Semicolon);
            return result;
        }

        private AST ParseBreakStatement()
        {
            AST result;
            AST label = new AST();
            label.NodeKind = Nodes.Empty;
            Match(Tokens.Break);

            if (CurrentToken.kind == Tokens.Identifier)
            {
                label = new AST();
                label.NodeKind = Nodes.Identifier;
                label.Name = CurrentToken.value;
            }
            result = new AST();
            result.NodeKind = Nodes.Break;
            result.ChildNodes.Add(label);
            return result;
        }

        private AST ParseContinueStatement()
        {
            AST label = new AST();
            label.NodeKind = Nodes.Empty;
            AST result;

            Match(Tokens.Continue);
            if (CurrentToken.kind == Tokens.Identifier)
            {
                label.NodeKind = Nodes.Identifier;
                Match(Tokens.Identifier);
            }
            result = new AST();
            result.NodeKind = Nodes.Continue;
            result.ChildNodes.Add(label);
            Match(Tokens.Semicolon);
            return result;
        }

        /// <summary>
        /// WhileStatement
	  ///     	:    WHILE LPAREN Expression RPAREN Statement
        /// </summary>
        /// <returns></returns>
        private AST ParseWhileStatement()
        {
            AST result;
            AST exp;
            AST body;
            Match(Tokens.While);
            Match(Tokens.OpenParenthesis);
            exp = ParseExpression(false);
            Match(Tokens.CloseParenthesis);
            body = ParseStatement();
            result = new AST();
            result.NodeKind = Nodes.While;
            result.ChildNodes.Add(exp);
            result.ChildNodes.Add(body);
            return result;
        }

        private AST ParseDoStatement()
        {
            AST result;

            AST condition;
            AST body;

            Match(Tokens.Do);
            body = ParseStatement();
            Match(Tokens.While);
            Match(Tokens.OpenParenthesis);
            condition = ParseExpression(false);
            Match(Tokens.CloseParenthesis);
            result = new AST();
            result.NodeKind = Nodes.Do;
            result.ChildNodes.Add(body);
            result.ChildNodes.Add(condition);
            return result;
        }

        private AST ParseForStatement()
        {
            AST result;
            //for(var obj in arr)
            AST obj = null;
            //for(initialize;condition;advance)
            AST condition = null;
            AST advance = null;
            AST initialize = new AST();
            AST body;
            bool isForIn = false;
            Match(Tokens.For);
            
            initialize.NodeKind = Nodes.Empty;
            Match(Tokens.OpenParenthesis);
            if (CurrentToken.kind != Tokens.Semicolon)
            {
                if (CurrentToken.kind == Tokens.Var)
                    initialize = ParseVarExpression(true);
                else
                    initialize = ParseExpression(true);
            }
            if (CurrentToken.kind == Tokens.In)
            {
                Match(Tokens.In);
                isForIn = true;
                obj = ParseExpression(false);
            }
            else
            {
                condition = new AST();
                condition.NodeKind = Nodes.Empty;
                if (CurrentToken.kind == Tokens.Semicolon)
                {
                    Match(Tokens.Semicolon);
                    condition = ParseExpression(false);
                }
                Match(Tokens.Semicolon);
                advance = new AST();
                advance.NodeKind = Nodes.Empty;
                if (CurrentToken.kind != Tokens.CloseParenthesis)
                {
                    advance = ParseExpression(false);
                }
            }
            Match(Tokens.CloseParenthesis);
            body = ParseStatement();
            if (isForIn)
            {
                result = new AST();
                result.NodeKind = Nodes.ForIn;

                result.ChildNodes.Add(initialize);
                result.ChildNodes.Add(obj);
                result.ChildNodes.Add(body);
            }
            else
            {
                result = new AST();
                result.NodeKind = Nodes.For;
                result.ChildNodes.Add(initialize);
                result.ChildNodes.Add(condition);
                result.ChildNodes.Add(advance);
                result.ChildNodes.Add(body);
            }
            return result;
        }
        /// <summary>
        /// VarExpression
        ///    	:    VAR VariableDeclarationList Semicolon
        ///     	;
        ///     VariableDeclarationList
        ///      	:    VariableDeclaration
        ///     	|    VariableDeclarationList Comma VariableDeclaration
        ///     	;
        /// </summary>
        /// <param name="noIn"></param>
        /// <returns></returns>
        private AST ParseVarExpression(bool noIn)
        {
            AST result = new AST();
            result.NodeKind = Nodes.Var;
            Match(Tokens.Var);
            result.ChildNodes.Add(ParseVariableDeclaration(noIn));
            while (CurrentToken.kind == Tokens.Comma)
            {
                Match(CurrentToken.kind);

                result.ChildNodes.Add(ParseVariableDeclaration(noIn));
            }

            return result;
        }
        /// <summary>
        /// VariableDeclaration
        ///    	:    Identifier
        ///    	|    Identifier Assign AssignmentExpression
	 ///    	;
        /// </summary>
        /// <param name="noIn"></param>
        /// <returns></returns>
        private AST ParseVariableDeclaration(bool noIn)
        {
            AST id;
            AST assignment = new AST();
            assignment.NodeKind = Nodes.Empty;

            AST result;

            if (CurrentToken.kind != Tokens.Identifier) throw new Exception("error");
            id = new AST();
            id.NodeKind = Nodes.Identifier;
            id.Name = CurrentToken.value;

            Match(Tokens.Identifier);
            if (CurrentToken.kind == Tokens.Assign)
            {
                Match(Tokens.Assign);
                assignment = ParseAssignmentExpression(noIn);
            }
            result = new AST();
            result.NodeKind = Nodes.Declaration;
            result.ChildNodes.Add(id);
            result.ChildNodes.Add(assignment);
            return result;
        }
        /// <summary>
        /// AssignmentExpression
	   ///    	:    ConditionalExpression
	    ///  	|    LeftHandSideExpression AssignmentOperator AssignmentExpression
	   ///   	;
	   ///    AssignmentOperator
	    ///   	:    EQUAL
	   ///    	|    STAR_EQUAL
	    ///   	|    FORWARD_SLASH_EQUAL
	   ///    	|    PERCENT_EQUAL
	   ///   	|    PLUS_EQUAL
	  ///     	|    MINUS_EQUAL
	   ///    	|    LESS_LESS_EQUAL
	   ///    	|    GREATER_GREATER_EQUAL
	  ///    	|    GREATER_GREATER_GREATER_EQUAL
	   ///   	|    AMPERSAND_EQUAL
	 ///    	|    CARET_EQUAL
	 ///     	|    PIPE_EQUAL
	  ///   	;
        /// </summary>
        /// <param name="noIn"></param>
        /// <returns></returns>
        private AST ParseAssignmentExpression(bool noIn)
        {
            //AST result = ParseConditionalExpression(notIn);
            //if (Tokens.AssignmentOperatorSet.Get(CurrentToken.kind))
            //{ 
            //    bool referenceable = true;
            //    if (result.NodeKind == Nodes.Group)
            //    {
            //        AST child = result.ChildNodes[0];
            //        while (child != null && child.NodeKind == Nodes.Group)
            //        {
            //            child = child.ChildNodes[0];
            //        }

            //        if(child == null || )
            //    }
            //}
            
            return null;
        }

        private AST ParseConditionalExpression(bool notIn)
        {
            AST result = ParseLogicalORExpression(notIn);
            if (CurrentToken.kind == Tokens.Question)
            {
                AST condition = result;
                AST trueCase = new AST();
                trueCase.NodeKind = Nodes.Empty;
                AST falseCase = new AST();
                falseCase.NodeKind = Nodes.Empty;
                Match(Tokens.Question);
                trueCase = ParseAssignmentExpression(notIn);
                Match(Tokens.Colon);
                falseCase = ParseAssignmentExpression(notIn);
                result = new AST();
                result.NodeKind = Nodes.Conditional;
                result.ChildNodes.Add(condition);
                result.ChildNodes.Add(trueCase);
                result.ChildNodes.Add(falseCase);
            }
            return result;
        }

        private AST ParseLogicalORExpression(bool notIn)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Expression
	    ///      	:    AssignmentExpression
	    ///  	|    Expression COMMA AssignmentExpression
	    ///    	;
        /// </summary>
        /// <param name="noIn"></param>
        /// <returns></returns>
        private AST ParseExpression(bool noIn)
        {
            AST result = ParseAssignmentExpression(noIn);
            if (CurrentToken.kind == Tokens.Comma)
            {
                AST commas = new AST();
                commas.NodeKind = Nodes.Comma;
                commas.ChildNodes.Add(result);

                while (CurrentToken.kind == Tokens.Comma)
                {
                    Match(Tokens.Comma);
                    AST node = ParseAssignmentExpression(noIn);
                    commas.ChildNodes.Add(node);
                }
                result = commas;
            }
            return result;
        }

        private AST ParseBlock()
        {
            AST result = new AST();
            result.NodeKind = Nodes.sourceElements;
            Match(Tokens.OpenCurlyBrace);
            while (CurrentToken.kind != Tokens.CloseCurlyBrace && CurrentToken.kind != Tokens.EOF)
                result.ChildNodes.Add(ParseStatement());

            Match(Tokens.CloseCurlyBrace);
            return result;
        }

        private AST ParseIfStatement()
        {
            AST result;

            AST condition;

            AST trueCase;
            AST falseCase = new AST();
            falseCase.NodeKind = Nodes.Empty;

            Match(Tokens.If);
            Match(Tokens.OpenParenthesis);
            condition = ParseExpression(false);
            Match(Tokens.CloseParenthesis);
            trueCase = ParseElement();
            if (CurrentToken.kind == Tokens.Else)
            {
                Match(Tokens.Else);
                falseCase = ParseElement();
            }
            result = new AST();
            result.NodeKind = Nodes.If;
            result.ChildNodes.Add(condition);
            result.ChildNodes.Add(trueCase);
            result.ChildNodes.Add(falseCase);
            return result;
        }

        private AST ParseUnaryExpression()
        {
            AST result = null;
            if (Tokens.UnaryExpressionSet.Get(CurrentToken.kind))
            {
                int kind = CurrentToken.kind;

                bool isMemberExpression = Tokens.PostfixExpressionSet.Get(CurrentToken.kind);
                lexer.GetNextToken();
                if (isMemberExpression)
                {
                    result = ParseMemberExpression(true);
                }
                else
                {
                    result = ParseUnaryExpression();
                }

                switch (kind)
                {
                    case Tokens.Delete:
                        AST temp = new AST();
                        temp.NodeKind = Nodes.Delete;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Not:
                        temp = new AST();
                        temp.NodeKind = Nodes.Not;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Minus:
                        temp = new AST();
                        temp.NodeKind = Nodes.Minus;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Decrement:
                        temp = new AST();
                        temp.NodeKind = Nodes.Pre_Decrement;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Plus:
                        temp = new AST();
                        temp.NodeKind = Nodes.Plus;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Increment:
                        temp = new AST();
                        temp.NodeKind = Nodes.Pre_Increment;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.BitwiseComplement:
                        temp = new AST();
                        temp.NodeKind = Nodes.BitwiseComplement;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Typeof:
                        temp = new AST();
                        temp.NodeKind = Nodes.TypeOf;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    case Tokens.Void:
                        temp = new AST();
                        temp.NodeKind = Nodes.Void;
                        temp.ChildNodes.Add(result);
                        result = temp;
                        break;
                    default:
                        break;
                }
            }
            else
            {
                result = ParseMemberExpression(true);
                if (CurrentToken.next.kind != Tokens.EndOfLine && Tokens.PostfixExpressionSet.Get(CurrentToken.kind))
                {
                    int kind = CurrentToken.kind;
                    lexer.GetNextToken();

                    switch (kind)
				    {
					    case Tokens.Increment:
						    AST temp = new AST();
                            temp.NodeKind = Nodes.Post_Increment;
						    temp.ChildNodes.Add(result);
						    result = temp;
						    break;

					    case Tokens.Decrement:
                            temp = new AST();
                            temp.NodeKind = Nodes.Post_Decrement;
                            temp.ChildNodes.Add(result);
						    result = temp;
                            break;

					    default:
						    break;
				    }
                }
            }
            return result;
        }
        /// <summary>
        /// MemberExpression
        ///     	:    PrimaryExpression
        /// 	|    FunctionExpression
        ///	|    MemberExpression LBRACKET Expression RBRACE
        ///	|    MemberExpression DOT IDENTIFIER
        ///	|    NEW MemberExpression Arguments
        ///	;
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private AST ParseMemberExpression(bool isInvocable)
        {
            AST result = null;
            switch (CurrentToken.kind)
            { 
                case Tokens.Function:
                    result = ParseFunctionDeclaration(false);
                    break;
                case Tokens.New:
                    Match(Tokens.New);
                    AST memberExpression = ParseMemberExpression(false);
                    AST arguments = new AST();
                    arguments.NodeKind = Nodes.Empty;
                    if (CurrentToken.kind == Tokens.OpenParenthesis)
                    {
                        Match(Tokens.OpenParenthesis);
                        if (CurrentToken.kind != Tokens.CloseParenthesis)
                        {
                            arguments = ParseArgumentList();
                        }
                        else
                        {
                            Match(Tokens.CloseParenthesis);
                        }
                    }
                    result = new AST();
                    result.NodeKind = Nodes.Construct;
                    result.ChildNodes.Add(memberExpression);
                    result.ChildNodes.Add(arguments);
                    break;
                default:
                    result = ParsePrimaryExpression();
                    break;
            }

            memberTail: while (Tokens.PostfixMemberExpressionSet.Get(CurrentToken.kind))
            {
                switch (CurrentToken.kind)
                { 
                    case Tokens.Dot:
                        AST identifier;
                        Match(Tokens.Dot);
                        if (CurrentToken.kind == Tokens.Identifier)
                        {
                            identifier = new AST();
                            identifier.NodeKind = Nodes.Identifier;
                            identifier.Name = CurrentToken.value;
                            Match(Tokens.Identifier);

                            AST temp = new AST();
                            temp.NodeKind = Nodes.Get_Property;
                            temp.ChildNodes.Add(result);
                            temp.ChildNodes.Add(identifier);
                            result = temp;
                        }
                        break;
                    case Tokens.OpenSquareBracket:
                        Match(Tokens.OpenSquareBracket);
                        AST exp = ParseExpression(false);
                        Match(Tokens.CloseSquareBracket);
                        AST temp1 = new AST();
                        temp1.NodeKind = Nodes.Get_Element;
                        temp1.ChildNodes.Add(result);
                        temp1.ChildNodes.Add(exp);
                        result = temp1;
                        break;
                    case Tokens.OpenParenthesis:
                        if (!isInvocable)
                            goto memberTail;

                        AST arguments = new AST();
                        arguments.NodeKind = Nodes.Empty;
                        Match(Tokens.OpenParenthesis);

                        if (CurrentToken.kind != Tokens.CloseParenthesis)
                        {
                            arguments = ParseArgumentList();
                        }
                        Match(Tokens.CloseParenthesis);
                        temp1 = new AST();
                        temp1.NodeKind = Nodes.Invoke;
                        temp1.ChildNodes.Add(result);
                        temp1.ChildNodes.Add(arguments);
                        result = temp1;
                        break;
                    default: break;

                }
            }
            return result;
        }

        private AST ParsePrimaryExpression()
        {
            throw new NotImplementedException();
        }

        private AST ParseArgumentList()
        {
            throw new NotImplementedException();
        }

    }
}